Моніторинг системних викликів створення обігу та видалення сегментів пам`яті, що розділяється в ОС Linux

[ виправити ] текст може містити помилки, будь ласка перевіряйте перш ніж використовувати.

скачати

Факультет інформатики і систем управління
Кафедра ПЗ ЕОМ та інформаційні технології
Курсова Робота
На тему: Моніторинг системних викликів створення, обігу та видалення сегментів пам'яті, що розділяється в ОС Linux

Зміст
1. Введення
2. Аналітична частина
2.1. Архітектура ОС Linux
2.2. Перехоплення і моніторинг системних викликів
2.3. Засоби IPC. Системний виклик sys_ipc
2.4. Колективна пам'ять (Shared Memory)
2.5. Системні виклики shmget, shmat, shmctl, shmdt
3. Конструкторська частина
3.1. Технічні вимоги до системи. Перекомпіляція ядра
3.2. Написання та впровадження модуля ядра
3.3. Вибір мови програмування
3.4. Структура програмного забезпечення
3.5. Структури даних
3.6. Реалізація моніторингу створення, управління та видалення сегментів пам'яті, що розділяється
3.7. Користувальницький інтерфейс
4. Висновок
Список використаної літератури

1. Введення
З розвитком операційних систем і збільшенням складності програм з'явилася необхідність в обміні даними між процесами. Саме тому в операційну систему зараз вбудовується безліч механізмів, які забезпечують так званий Interproccess Communication (IPC), тобто межпроцессное взаємодію.
Однією з найпоширеніших операційних систем на даний момент є ОС Linux, яка представляє собою інтерактивну систему з відкритим кодом, розроблену для одночасної підтримки кількох процесів і декількох користувачів. Традиційний підхід ОС сімейства Unix полягає в тому, щоб дозволити багатопроцесорним системам запускати додатки в окремих процесах для скорочення часу, необхідного на виконання специфічних завдань. Засоби IPC дозволяють уникнути створення величезних програм з великою кількістю функцій, а замінити їх набором окремих, малих додатків, здатних обмінюватися даними між собою.
ОС Linux належить до стандарту Unix System V, який підтримує три види IPC-об'єктів:
· Черги повідомлень, які представляють собою зв'язний список в адресному просторі ядра. Повідомлення можуть посилатися у чергу по порядку і діставатися з черги кількома різними шляхами.
· Семафори - лічильники, керуючі доступом до загальних ресурсів. Найчастіше вони використовуються як блокуючий механізм, який не дозволяє одному процесу захопити ресурс, поки що цим ресурсом користується інший.
· Пам'ять, що розподіляється - засіб, що забезпечує можливість наявності загальної пам'яті у декількох процесів.
Механізм взаємодії, заснований на сегментах Shared Memory, є більш швидким, ніж черги повідомлень і семафори. Тут немає ніякого посередництва у вигляді каналів, черг повідомлень і т.п., що значно спрощує цей механізм. Тому даний курсовий проект присвячений саме цьому типу між процесами взаємодії.
Моніторинг створення, видалення сегментів пам'яті, що розділяється і звернення до них дозволяє простежити, який користувач має справу з об'єктами Shared Memory і отримати інформацію про те, сегмент якого розміру і для яких цілей запитується, за якою адресою він знаходиться у віртуальній пам'яті і т.д.

2. Аналітична частина
2.1 Короткий огляд архітектури ОС Linux
Щоб зрозуміти принцип роботи програми моніторингу, для початку варто коротко розглянути архітектуру даної операційної системи. Linux, як операційну систему сімейства UNIX, можна розглядати у вигляді піраміди, в основі якої розташовується апаратне забезпечення, що складається з центрального процесора, пам'яті, дисків, терміналів та інших пристроїв (рис. 1). Функції самої ОС полягають в управлінні апаратним забезпеченням і надання всім програмам інтерфейсу системних викликів, що дозволяє створювати процеси, файли та інші ресурси і керувати ними.

Рис. 1. Структура ОС UNIX
Програми звертаються до системних викликів, поміщаючи аргументи в регістри центрального процесора і виконуючи команду емулювати переривання для перемикання з користувальницького режиму в режим ядра і передачі управління операційній системі. Стандарт POSIX визначає бібліотечні процедури, що відповідають системним викликам, їх параметри, що вони повинні робити і який результат повертати.
Таким чином, взаємодія з ядром відбувається за допомогою стандартного інтерфейсу системних викликів, який представляє собою набір послуг ядра і визначає формат запитів на послуги. Фактично, це набір функцій, реалізованих в ядрі ОС. Процес запитує послугу шляхом системного виклику певної процедури ядра, зовні схожого на звичайний виклик бібліотечної функції. Ядро від імені процесу виконує запит і повертає процесу необхідні дані. Будь-який запит додатки користувача в кінцевому підсумку трансформується в системний виклик, який виконує запитувана дію.
Перш ніж реалізувати перехоплення будь-якого системного виклику, потрібно докладніше розглянути механізм системних викликів.
Точка переходу в ядрі, називається system_call. Процедура, яка там знаходиться, перевіряє номер системного виклику, який повідомляє ядро, яку саме послугу запитує процес. Потім, вона переглядає таблицю системних викликів (sys_call_table) відшукує адресу функції ядра, яку слід викликати, після чого викликається потрібна функція. Після закінчення роботи системного виклику, виконується ряд додаткових перевірок і лише після цього управління повертається зухвалому процесу (або іншому процесу, якщо викликає процес вичерпав свій квант часу).
2.2 Перехоплення і моніторинг системних викликів
Перехоплення системних викликів можна здійснити наступними способами:
· Методом прямого доступу до адресного простору ядра
· За допомогою завантаження модуля ядра
Прямий доступ до адресного простору ядра забезпечує файл пристрою / dev / kmem. У цьому файлі відображено все доступне віртуальний адресний простір. Для роботи з файлом kmem використовуються стандартні системні функції - open (), read (), write (). Відкривши стандартним способом / dev / kmem, ми можемо звернутися до будь-якою адресою в системі, поставивши його як зсув у цьому файлі.
Звернення до системних функцій здійснюється за допомогою завантаження параметрів функції в регістри процесора і наступним викликом програмного переривання 0x80. Оброблювач цього переривання, функція system_call, поміщає параметри виклику в стек, витягує з таблиці sys_call_table адресу викликається системної функції і передає управління за цією адресою.
Маючи повний доступ до адресного простору ядра, ми можемо отримати весь вміст таблиці системних викликів, тобто адреси всіх системних функцій. Змінивши адресу будь-якого системного виклику, ми, тим самим, здійснимо його перехоплення. Але для цього необхідно знати адресу таблиці, або, іншими словами, зміщення у файлі / dev / kmem, за яким ця таблиця розташована.
Для обчислення адреси функції system_call з таблиці IDT необхідно витягти шлюз переривання int $ 0x80, а з нього - адреса відповідного обробника, тобто адреса функції system_call. Знайшовши сигнатуру цієї команди у файлі / dev / kmem, ми знайдемо і адреса таблиці системних викликів.
Але ми працює в адресному просторі користувача, а новий системний виклик необхідно розмістити в адресному просторі ядра. Для цього необхідно отримати блок пам'яті в просторі ядра і розмістити в цьому блоці новий системний виклик.
Виділити пам'ять в просторі ядра можна за допомогою функції kmalloc. Але викликати безпосередньо функцію ядра з адресного простору користувача не можна, тому для цього використовується спеціальний алгоритм, в результаті якого в нашому розпорядженні буде блок пам'яті, розташований в просторі ядра.
Неважко помітити, що даний механізм досить трудомісткий, тому на практиці часто використовується інший метод.
Перехоплення системних викликів реалізується за допомогою механізму завантаження модуля ядра (загальноприйняте скорочення LKM - Loadable Kernel Module). LKM представляє собою програмний код, що виконується в просторі ядра. Головною особливістю цього механізму є можливість динамічного завантаження і вивантаження без необхідності перезавантаження всієї системи або перекомпіляції ядра. Модулі розширюють функціональні можливості. Наприклад, один з різновидів модулів ядра, драйвери пристроїв, дозволяють ядру взаємодіяти з апаратурою комп'ютера. За відсутності підтримки модулів довелося б писати монолітні ядра і додавати нові можливості прямо в ядро. При цьому, після додавання в ядро ​​нових можливостей, довелося б перезавантажувати систему.
Детальніше принцип створення та завантаження модуля ядра буде описаний в конструкторському розділі.
Для реалізації модуля, перехоплює системний виклик, необхідно визначити алгоритм перехоплення, представлений на рис. 2.

SHAPE \ * MERGEFORMAT
Зберегти покажчик на оригінальний виклик.
Створити функцію, що реалізовує новий системний виклик.
У таблиці sys_call_table зробити заміну системних викликів
Після закінчення роботи відновити оригінальний системний виклик
Початок
Кінець

Рис.2. Алгоритм перехоплення системного виклику за допомогою LKM
Іншими словами, в ядро ​​завантажується модуль, який
· Зберігає покажчик на оригінальний (вихідний) виклик для можливості його відновлення.
· Містить функцію, що реалізовує новий системний виклик.
· У таблиці системних викликів sys_call_table робить заміну викликів (налаштовує відповідний покажчик на новий системний виклик)
· По закінченні роботи (при вивантаженні модуля) відновлює оригінальний системний виклик, використовуючи раніше збережений покажчик
Даний механізм дозволяє створити монітор - програму, яка відстежує виклики конкретних системних функцій, перехоплює і зберігає інформацію про їх параметрах, що й було зроблено в даному курсовому проекті.
2.3. Засоби IPC. Системний виклик sys _ ipc
Однією з найважливіших особливостей ОС сімейства UNIX вважається реалізація механізмів IPC, або, іншими словами, між процесами взаємодії. Термін має на увазі різні засоби обміну даними між процесами, що стартував в одній системі.
На високому рівні можна розділити межпроцессное взаємодія на такі найбільш великі і важливі розділи:
· Повідомлення: канали (pipes) і
черги повідомлень (pipes and message queues)
· Пам'ять, що розподіляється (Shared memory)
· Віддалений виклик процедур - RPC (remote procedure calls)
· Синхронізація: семафори і будь-які види блокування
· Мережеве взаємодія (API сокетів)
З наявних типів IPC наступні три можуть бути віднесені до
System V IPC, тобто до методів взаємодії процесів, що відповідає стандарту System V:
· Черги повідомлень
· Семафори
· Пам'ять, що розподіляється
Термін «System V IPC» говорить про походження цих коштів: вперше вони з'явилися в Unix System V. У них багато спільного, наприклад, схожі функції, за допомогою яких організується доступ до об'єктів, і й форми зберігання інформації в ядрі.
Кожен об'єкт IPC (черга повідомлень, семафор або сегмент пам'яті, що розділяється) володіє унікальним ідентифікатором (Id), який дозволяє ядру ОС ідентифікувати цей об'єкт. Наприклад, для того, щоб послатися на певний сегмент пам'яті, що розділяється, необхідно знати унікальний ідентифікатор, призначений цього сегменту. Але слід зазначити, що ідентифікатор IPC унікальний тільки для свого типу об'єктів.
Для генерації ідентифікатора необхідний унікальний ключ. Притому користувальницькі додатки повинні генерувати свої власні ключі спеціальної системної функцією.
Коли процес намагається звернутися до якого-небудь об'єкту IPC (а саме, семафора, черги повідомлень або сегменту пам'яті, що розділяється), він здійснює системний виклик sys_ipc. Під зверненням тут розуміється запит на створення, видалення об'єкта, управління його параметрами. При цьому функції sys_ipc передається якийсь ідентифікатор, однозначно визначає, що саме запитує процес.
Таким чином, перехопивши цей системний виклик, можна відстежити процес створення, видалення сегментів пам'яті, що розділяється і зміни його параметрів.
2.4 Пам'ять, що розподіляється (Shared Memory)
Даний курсового проекту полягає в моніторингу використання лише одного із засобів IPC, а саме пам'яті, що розділяється, яка може бути найкращим чином описана як відображення ділянки (сегмента) пам'яті, який буде розділений між більш ніж одним процесом. Shared Memory є найбільш швидким засобом між процесами взаємодії. Після відображення області пам'яті в адресний простір процесів, спільно її використовують, для передачі даних більше не потрібно участі ядра. При використанні цього засобу ділянки віртуального адресного простору різних процесів відображаються на одні й ті ж адреси реальної пам'яті.
При роботі із загальним сегментом пам'яті один з процесів повинен створити сегмент розділяється (загальною) пам'яті, вказавши необхідний розмір сегмента, і отримати його ідентифікатор. Цей ідентифікатор потім використовується процесом-творцем для виконання керуючих операцій з пам'яттю,.
Отримавши ідентифікатор розділяється сегмента пам'яті (створивши сегмент або отримавши його ідентифікатор від іншого процесу), процес повинен "приєднати" сегмент. Операція приєднання повертає адресу розділяється сегмента у віртуальному адресному просторі процесу. Віртуальний адресу одного і того ж сегменту може бути різним для різних процесів. Далі процеси ведуть читання і запис даних у сегменті пам'яті, що розділяється, використовуючи для цього ті ж самі машинні команди, що і при роботі зі звичайною пам'яттю.
Процес, який закінчив роботу із сегментом пам'яті, що розділяється повинен "від'єднати" його, а по закінченні використання сегмента всіма процесами він повинен бути знищений.
При одночасній роботі процесів із загальною областю пам'яті, можливо, потрібна синхронізація їх доступу до області. За забезпечення такої синхронізації повністю відповідає програміст, який може використовувати для цього алгоритми, що виключають конфлікти одночасного доступу або системні засоби, наприклад, семафори.
2.5 Системні виклики shmget, shmat, shmctl, shmdt
У ядрі Linux, всі виклики, що мають відношення до system V IPC діспетчерізуются через функцію sys_ipc (розміщену у файлі arch/i386/kernel/sys_i386.c). Для ідентифікації системного виклику, sys_ipc використовує номер цього виклику.
В ОС Linux механізм поділюваних сегментів пам'яті забезпечується чотирма системними викликами: shmget, shmctl, shmat, shmdt. У функції sys_ipc вони мають номери SHMGET, SHMAT, SHMCTL, SHMDT відповідно.
Функції int shmget (key_t key, size_t size, int flag) дозволяє створити новий сегмент пам'яті, що розділяється або підключитися до існуючого. Повертане числове значення є ідентифікатором сегмента, який використовується при подальших операціях з ним.
Аргумент key - унікальний ключ, необхідний для створення ідентифікатора. size вказує необхідний розмір сегменту в байтах.
flag представляє собою комбінацію прапорів доступу на читання і запис
Після створення або відкриття сегмента пам'яті, що розділяється його потрібно підключити до адресного простору процесу викликом
void * shmat (int shmid, void * shmaddr, int flag), який повертає початкову адресу пам'яті, що розділяється в адресному просторі викликав процесу. Аргумент shmid - ідентифікатор пам'яті, що розділяється, повернутий shmget. Shmaddr визначає бажаний адресу «прив'язки» сегмента. Але в більшості випадків система сама вибирає початковий адресу для викликав процесу. За замовчуванням сегмент підключається для читання і запису, але в аргументі flag модно вказати константу SHM_RDONLY, яка дозволить встановити доступ тільки на читання.
Після завершення роботи з сегментом його слід відключити викликом int shmdt (void * shmaddr), який отримує в якості аргументу адресу, повернений функцією shmat. Слід окремо зазначити, що ця функція не видаляє сегмент пам'яті, що розділяється, а всього лише знімає «прив'язку» до процесу.
Функція int shmctl (int shmid, int cmd, struct shmid_ds * buff) дозволяє виконувати різні операції з сегментом пам'яті, що розділяється. Аргумент cmd може приймати такі значення:
IPC_RMID - видалення сегменту з ідентифікатором shmid;
IPC_SET - установка значень полів структури shmid_ds для сегменту рівними значенням відповідним полів структури, на яку вказує buff: shm_perm.uid, shm_perm.gid, shm_perm.mode
IPC_STAT - повертає зухвалому процесу (через аргумент buff) поточне значення структури shmid_ds для зазначеного сегмента пам'яті, що розділяється.
Сегменти пам'яті в Unix / Linux (як і семафори) не мають зовнішніх імен. При отриманні ідентифікатора сегмента процес користується числовим ключем. Розробники незв'язаних процесів можуть домовитися про загальне значення ключа, який вони будуть використовувати, але у них немає гарантії в тому, що це ж значення ключа не буде використано кимось ще. Гарантовано унікальний сегмент можна створити з використанням ключа IPC_PRIVATE, але такий ключ не може бути зовнішнім. Тому сегменти використовуються, як правило, спорідненими процесами, які мають можливість передавати один одному їх ідентифікатори, наприклад, через успадковані ресурси або через параметри виклику дочірньої програми.
Таким чином, для створення монітора пам'яті, що розділяється з таблиці системних викликів слід отримати адресу обробника sys_ipc (), перехопити його, а потім, знаючи, який з вищеописаних викликів здійснює система, вважати відповідні дані.

3. Конструкторська частина
3.1 Технічні вимоги до системи. Перекомпіляція ядра
Для створення і тестування даної програми використовувалася ОС Linux SUSE 10 (версія ядра 2.6.13-15). Але з метою запобігання потенційної небезпеки, пов'язаної з підміною адрес системних викликів, ядро, починаючи з версії 2.5.41, не експортує таблицю sys_call_table, доступ до якої необхідний для створення програми моніторингу системних викликів. Тому, щоб мати можливість перехоплювати системні виклики, треба накласти наступну «латку» і потім перекомпілювати ядро.
"Латка" на ядро ​​(export_sys_call_table_patch_for_linux_2.6.x)
--- Kernel / kallsyms.c.orig 2003-12-30 07:07:17.000000000 +0000
+ + + Kernel / kallsyms.c 2003-12-30 07:43:43.000000000 +0000
@ @ -184,7 +184,7 @ @
iter-> pos = pos;
return get_ksymbol_mod (iter);
}
-
+
/ * If we're past the desired position, reset to start. * /
if (pos <iter-> pos)
reset_iter (iter);
@ @ -291,3 +291,11 @ @

EXPORT_SYMBOL (kallsyms_lookup);
EXPORT_SYMBOL (__print_symbol);
+ / * START OF DIRTY HACK:
+ * Purpose: enable interception of syscalls as shown in the
+ * Linux Kernel Module Programming Guide. * /
+ Extern void * sys_call_table;
+ EXPORT_SYMBOL (sys_call_table);
+ / * See http://marc.free.net.ph/message/20030505.081945.fa640369.html
+ * For discussion why this is a BAD THING (tm) and no longer supported by 2.6.0
+ * END OF DIRTY HACK: USE AT YOUR OWN RISK * /
Ця латка протестована з ядрами 2.6. [0123], і може накладатися або не накладатися на інші версії.
Сценарій накладення следуюший:
#! / Bin / sh
cp export_sys_call_table_patch_for_linux_2.6.x / usr / src / linux /
cd / usr / src / linux /
patch-p0 <export_sys_call_table_patch_for_linux_2.6.x
Але такий спосіб ефективний тільки при збігу «заплатки» з версією ядра. Якщо «латка» з якихось причин не накладається, потрібно скопіювати вихідні файли ядра в окрему директорію, дописати в файл kernel / kallsyms.c після рядка
EXPORT_SYMBOL (__print_symbol);
наступне:
extern void * sys_call_table;
EXPORT_SYMBOL (sys_call_table);
Після цього відкрити Makefile і в рядку
EXTRAVERSION =
дописати нове ім'я ядра.
Після цього слід перезібрати ядро, виконавши наступну послідовність дій:
1) Видалення тимчасових файлів і налаштувань, отриманих при можливій попередньої збірці, командою
# Make mrproper
1) Налаштування ядра. Здійснюється однією зі следущих команд:
# Make xconfig
# Make menuconfig
# Make config
# Make oldconfig
Перший варіант (xconfig) для користувачів, у яких є графіка - запуститься графічна програмка для налаштування, решта - для консолі. Другий варіант (menuconfig) пропонує текстові меню для настройки. Третій (config) задає 1000 і 1 питання. Четвертий (oldconfig) потрібний якщо вже є сформований файл настройок. Config (можна використовувати файл настройок від старого ядра), при цьому варіанті задаються тільки ті питання які з'явилися в цій версії ядра.
2) Збирання ядра. Виконується командою від користувача root
# Make bzImage modules modules_install install
Перекомпіляція ядра відбувається досить довго. Після встановлення ядра, як правило, автоматично налаштовується і завантажувач. Тому після цього, слід перезавантажити систему вже від імені нового ядра.
3.2 Написання та впровадження модуля ядра
У програмі перехоплення системних викликів здійснено механізмом завантаження модуля ядра (LKM). В аналітичній частині були описані переваги, які отримує система при використанні даного механізму. Тепер варто розібратися, як він реалізується.
Кожен LKM складається мінімум з двох основних функцій:
· Int init_module (void), яку викликає insmod під час завантаження модуля
· Void cleanup_module (void), яку викликає rmmod
Функція init_module () виконує реєстрацію обробника якої-небудь події або заміщає будь-яку функцію в ядрі своїм кодом (який, як правило, виконавши якісь специфічні дії, викликає оригінальну версію функції в ядрі). Викликається при завантаженні LKM в пам'ять.
Функція cleanup_module () є повною протилежністю, вона виробляє "відкат" змін, зроблених функцією init_module (), що робить вивантаження модуля безпечною.
Будь-який завантажений модуль ядра заноситься в список / proc / modules, тому при вдалій завантаженні можна переконатися, що модуль став частиною ядра.
У даному курсовому проекті функція init_module () змінює відповідний певному системному виклику покажчик у sys_call_table і зберігає його первісне значення в змінній. Функція cleanup_module () відновлює покажчик у sys_call_table, використовуючи цю змінну.
У даному підході криються свої "підводні камені" через можливість існування двох модулів, що перекривають один і той же системний виклик. Наприклад, є два модулі, А і B. Нехай модуль A перекриває системний виклик open, своєю функцією A_open, а модуль B - функцією B_open. Першим завантажується модуль A, він замінює системний виклик open на A_open. Потім завантажується модуль B, який замінить системний виклик A_open на B_open. Модуль B вважає, що він підмінив оригінальний системний виклик, хоча насправді був підмінений виклик A_open, якщо модуль B вивантажити першим, то нічого страшного не відбудеться - він просто відновить запис у таблиці sys_call_table в значення A_open, який в свою чергу викликає оригінальну функцію sys_open. Однак, якщо першим буде вивантажений модуль А, а потім B, то система "звалиться". Модуль А відновить адреса в sys_call_table, який вказує на оригінальну функцію sys_open, "відсікаючи" таким чином модуль B від обробки дій по відкриттю файлів. Потім, коли буде вивантажений модуль B, він відновить адреса в sys_call_table на той, який запам'ятав сам, тому що він вважає його оригінальним. Тобто виклики будуть направлені у функцію A_open, якої вже немає в пам'яті.
На перший погляд, проблему можна вирішити, перевіркою - чи збігається адреса в sys_call_table з адресою нашої функції open і якщо не збігається, то не відновлювати значення цього виклику (таким чином B не буде "відновлювати" системний виклик), але це породжує іншу проблему . Коли вивантажується модуль А, він "бачить", що системний виклик був змінений на B_open і "відмовляється" від відновлення покажчика на sys_open. Тепер, функція B_open буде як і раніше намагатися викликати A_open, якій більше не існує в пам'яті, так що система "звалиться" ще раніше - до видалення модуля B.
Подібні проблеми роблять таку "підміну" системних викликів непридатною для широкого розповсюдження. З метою запобігання потенційної небезпеки, пов'язаної з підміною адрес системних викликів, ядро ​​більш не експортує sys_call_table. Але все ж таки отримати доступ до таблиці системних викликів можна, поставивши відповідну «латку», що було описано в попередньому параграфі.
3.3 Вибір мови програмування
Програма написана на мові С з використанням вбудованого в
ОС Linux компілятора GCC. Вибір мови заснований на тому, що вихідний код ядра, що надається системою, написаний на С, і використання іншої мови програмування в даному випадку було б недоцільним. До того ж він є потужним засобом для розробки практично будь-якої програми.
3.4 Структура програмного забезпечення
Програма складається з наступних об'єктів
1) завантажений модуль ядра Monitor.с
2) Модуль Start.с, який здійснює підготовку до активних модулів Monitor.с
3) Модуль Save.с, призначений для збереження отриманих даних і виведення їх на екран.
4) Модуль Test.с, що містить емулятор системних викликів для тестування програмного забезпечення.
Monitor.с представляє собою завантажений модуль ядра (LKM), написання та принцип завантаження якого були описані вище.
Крім двох основних функцій програма містить новий обробник системного виклику sys_ipc - функцію new_sys_ipc, яка, в залежності від прийнятих даних викликає функції:
my_shmget;
my_shmat;
my_shmctl;
my_shmdt;
представляють собою обробники системних викликів
shmget (), shmat (), shmctl (), shmdt () відповідно.
Також у модулі знаходяться функції, що відображають отримані дані в системному файлі / var / log / messages:
print_shmget_info ();
print_shmat_info ();
print_shmctl_info ();
print_shmdt_info ();
Модуль Test.c представляє собою програму, що дозволяє користувачеві
· Створити сегмент пам'яті, що розділяється
· Записати в нього дані
· Вважати дані
· Дізнатися режим доступу сегменту
· Видалити сегмент
Для цього призначені процедури:
· Void writeshm ();
· Void readshm ();
· Void removeshm ();
· Void seeuid ();
Модуль створений для тестування програми моніторингу.
Модулі Start.c і Save.c призначені для відображення даних, отриманих в результаті виконання програми моніторингу звернень до сегментів пам'яті, що розділяється, на екран і для збереження їх у файл.
3.5 Структури даних
Для кожного сегмента пам'яті, що розділяється ядро ​​зберігає нижченаведену структуру, визначену в заголовному файлі <sys/shm.h>. Даний програмний проект дозволяє відстежити процес зміни вмісту полів цих структур при виклику системної функції sys_ctl.
struct shmid_ds
{
struct ipc_perm shm_perm;
int shm_segsz;
time_t shm_atime;
time_t shm_dtime;
time_t shm_ctime;
unsigned short shm_cpid;
unsigned short shm_lpid;
short shm_nattch;
};
Значення полів структури:
shm_perm - права на виконання операції (структура визначена в
файлі <sys/ipc.h>)
shm_segsz - реальний розмір сегмента (у байтах)
shm_atime - час останнього підключення
shm_dtime - час останнього відключення
shm_ctime - час останньої зміни
shm_cpid - ідентифікатор процесу творця
shm_lpid - ідентифікатор процесу підключається останнім
shm_nattch - кількість поточних підключень сегмента
struct ipc_perm
{
key_t key;
ushort uid;
ushort gid;
ushort cuid;
ushort cgid;
ushort mode;
ushort seq;
};
Зі значенням полів
key - унікальний ключ IPC
uid - ідентифікатор користувача власника
gid - ідентифікатор групи власника
cuid - ідентифікатор користувача творця
cgid - ідентифікатор власника творця
mode - дозволу читання / запису
seq - послідовний номер каналу
Збережена окремо разом з ключем IPC-об'єкта інформація містить дані про власника і творця цього об'єкта (вони можуть відрізнятися) і режими восьмеричного доступу.
Модуль Monitor.c містить наступні структури даних для зберігання інформації про сегменті пам'яті, що розділяється, отриманої в результаті виконання програми
struct shmget_info
{
int cur_uid;
int key;
int shm_id;
int size;
int flag;
};
struct shmat_info
{
int cur_uid;
int shm_id;
unsigned long address;
};
struct shmctl_info
{
int cur_uid;
int shm_id;
int cmd;
struct shmid_ds * main;
int result;
};
struct shmdt_info
{
int cur_uid;
char * address;
int result;
};
key - унікальний ключ для визначення сегмента
shm_id - ідентифікатор сегмента
size - запитуваний розмір сегмента
flag - прапор, що визначає, з якою метою був здійснений системний
виклик sys_get:
· Процес створює новий сегмент поділюваної
пам'яті (flag = 0)
· Процес звертається до вже створеного сегменту
пам'яті, що розділяється (flag! = 0)
address - адреса початку сегмента в адресному просторі користувача
cmd - номер команди, що вказує на те, для яких дій був
проведений системний виклик sys_ctl:
· Отримати значення полів структури shmid_ds (IPC_STAT)
· Змінити значення полів в структурі shmid_ds (IPC_SET)
· Видалити сегмент (IPC_RMID)
main - отримана копія структури shmid_ds
result - результат виконання системного виклику (success або failed)
3.6 Реалізація моніторингу створення, управління та видалення сегментів пам'яті, що розділяється
Як вже було зазначено, відстежити звернення до сегментів пам'яті, що розділяється можна, перехопивши системний виклик sys_ipc, який крім інших аргумантов приймає параметр call, що визначає яку з системних функцій sys_get, sys_shmat, sys_ctl, sys_dt слід викликати.
Для перехоплення вихова sys_ipc, треба зробити наступне:
· У функції init_module () зберегти покажчик на оригінальний (вихідний) виклик - orig_sys_ipc - і в таблиці системних викликів sys_call_table налаштувати відповідний покажчик на новий системний виклик.
· Створити функцію, що реалізовує новий системний виклик - new_sys_ipc.
· У функції cleanup_module () восстанавіть оригінальний системний виклик, використовуючи раніше збережений покажчик.
У створеному обробнику системного виклику, в залежності від аргументу call, викликати функції обробки викликів sys_get, sys_shmat, sys_ctl, sys_dt, які зберігають отримані дані у відповідні структури даних, потім відображаються в ядро ​​і виводяться в системному файлі / var / log / messages.
Компіляція створеного модуля ядра здійснюється за допомогою команди
# Make
Незважаючи на всі свої достоїнства, утиліта make нічого не знає про проект, тому необхідно створити простий текстовий файл, який буде містити всі необхідні інструкції по збірці. Файл з інструкціями по збірці проекту називається Makefile.
У даному випадку, коли модуль складається з одного файлу, Makefile має вигляд, представлений на рис.3
obj-m + = monitor.o
all:
make-C / lib / modules / $ (shell uname-r) / build M = $ (PWD) modules
clean:
make-C / lib / modules / $ (shell uname-r) / build M = $ (PWD) clean
Рис.3. Makefile
Завантаження модуля в ядро ​​здійснюється командою
insmod. / <ім'я модуля>. ko
Вивантаження - командою
rmmod <ім'я модуля>
Перевірити, завантажений чи модуль у ядро, можна командою
# Lsmod,
яка видає список всіх завантажених модулів. lsmod у свою чергу звертається за необхідними відомостями до файлу / proc / modules.
3.7 Інтерфейс
Користувацький інтерфейс є повністю консольним. По-перше, тому що при мінімумі вхідних даних недоцільно створювати графічний додаток. По-друге, концепція ОС Linux передбачає широке використання можливостей командного рядка Shell.
Для того щоб запустити програму, необхідно виконати наступну послідовність дій:
· Запустити додаток start.o
· Завантажити модуль ядра
· Запустити тестову програму (або будь-який додаток ОС)
· Вивантажити модуль ядра
· Запустити додаток save.o
Тестуючі програма надає користувачеві меню, що дозволяє проводити вибір дій над сегментом пам'яті, що розділяється (рис.4).
Actions with Shared Memory Segment
w <text> - write text data into Segment
r - read data from Segment
d - delete Segment
u - get UID
Рис.4. Меню тестуючої програми
Результат відображається на екрані і зберігається у файлі. Структура файлу відображена на рис.5
Jun 2 2:33:53 terma kernel:
Jun 2 2:33:53 terma kernel: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~
Jun 2 2:33:53 terma kernel: Monitoring of Shared Memory Segments.
Jun 2 2:33:53 terma kernel:
Jun 2 2:34:16 terma kernel: SHMGET is called by UID: 0
Jun 2 2:34:16 terma kernel: key = 1392733089
Jun 2 2:34:16 terma kernel: shmID = 2588675
Jun 2 2:34:16 terma kernel: size = 88 byte
Jun 2 2:34:16 terma kernel: flag = 1968
Jun 2 2:34:16 terma kernel: [creating of new segment]
Jun 2 2:34:16 terma kernel:
Jun 2 2:34:16 terma kernel: SHMAT is called by UID: 0
Jun 2 2:34:16 terma kernel: shmID = 2588675
Jun 2 2:34:16 terma kernel: shmaddr = 40018000
Jun 2 2:34:16 terma kernel:
Jun 2 2:34:23 terma kernel: SHMGET is called by UID: 0
Jun 2 2:34:23 terma kernel: key = 1392733089
Jun 2 2:34:23 terma kernel: shmID = 2588675
Jun 2 2:34:23 terma kernel: size = 88 byte
Jun 2 2:34:23 terma kernel: flag = 0
Jun 2 2:34:23 terma kernel: [using segment as client]
Jun 2 2:34:23 terma kernel:
Jun 2 2:34:23 terma kernel: SHMAT is called by UID: 0
Jun 2 2:34:23 terma kernel: shmID = 2588675
Jun 2 2:34:23 terma kernel: shmaddr = 40018000
Jun 2 2:34:23 terma kernel:
Jun 2 2:34:23 terma kernel: SHMCTL is called by UID: 0
Jun 2 2:34:23 terma kernel: shmID = 2588675
Jun 2 2:34:23 terma kernel: cmd = IPC_STAT (2)
Jun 2 2:34:23 terma kernel: [getting current information about segment]
Jun 2 2:34:23 terma kernel: size of segment = 88 byte
Jun 2 2:34:23 terma kernel: key = 1392733089
Jun 2 2:34:23 terma kernel: uid = 0
Jun 2 2:34:23 terma kernel: gid = 0
Jun 2 2:34:23 terma kernel: cuid = 0
Jun 2 2:34:23 terma kernel: cgid = 0
Jun 2 2:34:23 terma kernel: mode = 0
Jun 2 2:34:23 terma kernel: [successfully]
Jun 2 2:34:23 terma kernel:
Jun 2 2:34:26 terma kernel: SHMGET is called by UID: 0
Jun 2 2:34:26 terma kernel: key = 1392733089
Jun 2 2:34:26 terma kernel: shmID = 2588675
Jun 2 2:34:26 terma kernel: size = 88 byte
Jun 2 2:34:26 terma kernel: flag = 0
Jun 2 2:34:26 terma kernel: [using segment as client]
Jun 2 2:34:26 terma kernel:
Jun 2 2:34:26 terma kernel: SHMAT is called by UID: 0
Jun 2 2:34:26 terma kernel: shmID = 2588675
Jun 2 2:34:26 terma kernel: shmaddr = 40018000
Jun 2 2:34:26 terma kernel:
Jun 2 2:34:26 terma kernel: SHMCTL is called by UID: 0
Jun 2 2:34:26 terma kernel: shmID = 2588675
Jun 2 2:34:26 terma kernel: cmd = IPC_RMID (0)
Jun 2 2:34:26 terma kernel: [segment marked for deletion]
Jun 2 2:34:26 terma kernel: [successfully]
Jun 2 2:34:26 terma kernel:
Jun 2 2:34:26 terma kernel: SHMDT is called by UID: 0
Jun 2 2:34:26 terma kernel: shmaddr: 40018000
Jun 2 2:34:26 terma kernel: [segment was deleted successfully]
Jun 2 2:34:26 terma kernel:
Jun 2 2:34:55 terma kernel:
Jun 2 2:34:55 terma kernel: The end.
Jun 2 2:34:55 terma kernel: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~
Рис.5 Файл Result

Висновок
В результаті виконання даної курсової роботи було вивчено механізм між процесами взаємодії (IPC) на основі сегментів пам'яті, що розділяється. Реалізовано моніторинг системних викликів, що звертаються до об'єктів Shared Memory, а саме створення, видалення сегментів пам'яті, що розділяється і звернення до них в ОС Linux. У результаті чого були отримані дані про сегменти пам'яті, що розділяється, такі як ідентифікатори користувача та групи власника, запитуваний і реальний розміри сегмента, адреса прив'язки сегмента в адресному просторі користувача та інші.

Список використаної літератури
1) «Linux Programmer's Guide», Sven Goldt, Sven van der Meer, Skott Burkett, Matt Welsh
2) «The Linux Kernel Module Programming Guide», А Peter Jay Salzman, Michael Burian, Ori Pomerantz
3) «Перехоплення системних викликів», стаття з журналу «Системний адміністратор», В. Мєшков
4) «Сучасні операційні системи», Е. Таненбаум

5) «Механізми межпроцессное взаємодій в операційній системі Unix» Сергій Кузнєцов

6) «Unix. Взаємодія процесів »Вільям Стівенс

Додати в блог або на сайт

Цей текст може містити помилки.

Програмування, комп'ютери, інформатика і кібернетика | Курсова
69.2кб. | скачати


Схожі роботи:
Моніторинг віртуальної пам`яті в ОС Linux
Механізм обслуговування системних викликів
Організація пам`яті СП Доступ до пам`яті Блоки пам`яті
Характеристики процесора та внутрішньої пам`яті комп`ютера швидкодію розрядність обсяг пам`яті
Два напрямки створення пам яті майбутнього
Види пам`яті витісняють статичну пам`ять
Привабливість сегментів ринку аналіз оцінка і вибір цільових сегментів
Пам`ять і закони пам`яті
Психофізіологія пам`яті
© Усі права захищені
написати до нас